import Config from "./Config.js"
import { assign } from "../utils/index.js"
import { MongoClient } from "mongodb"
/**
 * @class DataProvider
 * @classdesc 数据库相关操作封装
 * @author Niyang
 */
export default class DataProvider {
    constructor(options = {}) {
            this.cfg = assign({}, Config, options)
        }
        /**
         * @description 链接数据库
         * @param {String} url 
         * @param {Object} opts 
         * @returns Promise<MongoClient>
         */
    connect(url) {
            return MongoClient.connect(url)
        }
        /**
         * @description 获取数据库
         * @param {*} client 
         * @param {*} name 
         * @param {*} opts 
         * @returns DB实例
         */
    db(client, name, opts) {
            let options = this.cfg.dbOptions || opts
            return client.db(name, options)
        }
        /**
         * @description 查询数据
         * @param {*} name 
         * @param {*} filter 
         * @param {*} sort 
         * @returns 
         */
    find(name, filter, sort, cursor = {}) {
            return new Promise((resolve, reject) => {
                this.connect(this.cfg.url).then(client => {
                    this.db(client, this.cfg.db)
                        .collection(name)
                        .find(filter)
                        .project(cursor)
                        .sort(sort)
                        .toArray().then(data => {
                            resolve(data)
                        }).catch(err => {
                            reject(err)
                        }).finally(() => {
                            client.close()
                        })
                }).catch(err => {
                    reject(err)
                })
            })
        }
        /**
         * @description 分页查询
         * @param {*} name 
         * @param {*} filter 
         * @param {*} sort 
         * @param {*} pagination 
         * @returns 
         */
    findAndPaginate(name, filter, sort, pagination) {
            let size = pagination.size || 10;
            let page = pagination.page || 1
            return new Promise((resolve, reject) => {
                this.connect(this.cfg.url).then(client => {
                    this.db(client, this.cfg.db)
                        .collection(name)
                        .find(filter)
                        .sort(sort)
                        .skip(size * (page - 1))
                        .limit(size)
                        .toArray()
                        .then(data => {
                            resolve(data)
                        }).catch(err => {
                            reject(err)
                        }).finally(() => {
                            client.close()
                        })
                }).catch(err => {
                    reject(err)
                })
            })
        }
        /**
         * @description 查询
         * @param {*} name 
         * @param {*} filter 
         * @returns 
         */
    findOne(name, filter) {
        return new Promise((resolve, reject) => {
            this.connect(this.cfg.url).then(client => {
                this.db(client, this.cfg.db)
                    .collection(name)
                    .findOne(filter)
                    .then(data => {
                        resolve(data)
                    }).catch(err => {
                        reject(err)
                    }).finally(() => {
                        client.close()
                    })
            }).catch(err => {
                reject(err)
            })
        })
    }

    count(name, filter) {
        return new Promise((resolve, reject) => {
            this.connect(this.cfg.url).then(client => {
                this.db(client, this.cfg.db)
                    .collection(name)
                    .count(filter)
                    .then(data => {
                        resolve(data)
                    }).catch(err => {
                        reject(err)
                    }).finally(() => {
                        client.close()
                    })
            }).catch(err => {
                reject(err)
            })
        })
    }
}